// 服务器文件
const http = require("http"); // 引入 node.js 原生的 http 模块
const { Server } = require("socket.io");
const Y = require("yjs");
const { Awareness } = require("y-protocols/awareness");
const axios = require("axios");

// 创建一个 http 服务器
const server = http.createServer();
// 基于 http 服务器创建 websocket 服务器
const io = new Server(server, {
  cors: "*",
});

// 这个 map 用于存储每个房间对应的文档和光标状态信息
// 类似于 { doc, awareness }
// 每个方法会独立的管理自己的文档和光标状态
const docs = new Map();

// 当有客户端连接到当前的 websocket 服务器的时候，会触发该事件
// 并且连接过来的客户端会有一个 socket 传递过来
io.on("connection", (socket) => {
  let currentRoom = null; // 记录当前 socket 加入的时候的房间名

  socket.on("join-room", async (roomName) => {
    currentRoom = roomName; // 保存当前加入的房间名

    // 将 socket 加入到指定的房间，方便后面进行群发
    socket.join(roomName);

    if (!docs.has(roomName)) {
      // 进入此分支，说明当前的这个房间是第一次被访问
      // 第一次访问，我们需要创建全新的 yjs 副本
      const doc = new Y.Doc();
      const awareness = new Awareness(doc);

      // 这里需要增加一段逻辑：需要获取该文档（roomName）已有的内容
      try {
        const res = await axios.get(
          `http://localhost:7001/api/doc/${roomName}`
        );

        const result = res.data;
        // 有了文档内容之后，将文档内容填充到 yjs 的副本里面
        if (result.code === 0 && result.data && result.data.content) {
          const ytext = doc.getText("codemirror");
          ytext.insert(0, result.data.content);
        } else {
          console.log("获取文档内容失败，初始化为新文档", result);
        }
      } catch (error) {
        console.error("网络请求故障，获取文档初始内容失败，请稍候再试", error);
      }

      // 接下来保存到当前的房间里面
      docs.set(roomName, { doc, awareness });
    }

    // 根据 roomName 获取对应的 doc 和 awareness
    const { doc } = docs.get(roomName);

    // 1. 文档同步 - 服务器需要将文档的状态发送给新加入的客户端
    const state = Y.encodeStateAsUpdate(doc);
    socket.emit("sync-doc", state.buffer);
    
    // 2. 监听客户端发送过来的增量更新
    socket.on("update", (update) => {
      const binary = new Uint8Array(update); // 首先将 ArrayBuffer 转为 Uint8Array
      // 应用到服务器的 doc 上面
      Y.applyUpdate(doc, binary);
      // 接下来还需要将这个更新广播给当前房间的其他人
      socket.to(roomName).emit("update", binary.buffer);
    });

    // 3. 监听客户端发来的 awareness 光标状态
    socket.on("awareness-update", (update) => {
      // 这边不需要解析，直接广播给其他客户端即可
      socket.to(roomName).emit("awareness-update", update);
    });

    // 4. 断开连接
    socket.on("disconnect", () => {
      if (currentRoom) socket.leave(currentRoom);
    });
  });
});

server.listen("1234", () => {
  console.log(`Websocket 服务器已启动，监听1234端口`);
});



// 010101 这是 字符串 不说 二进制数据
// JavaScript中的Buffer、ArrayBuffer与Uint8Array深度解析
// 一、核心概念与作用概述
// 1. Buffer (Node.js特有)
// Buffer是Node.js中用于直接操作内存的二进制数据容器，它提供了一种在V8堆外分配固定大小内存的方式。Buffer实例类似于整数数组，但对应的是原始内存分配而非JavaScript数组。

// ‌主要作用‌：

// 处理TCP流和文件系统操作等I/O任务
// 高效存储和操作二进制数据(如图像、音频等)
// 替代传统字符串处理二进制数据(避免编码问题)
// 2. ArrayBuffer
// ArrayBuffer是JavaScript中表示通用的、固定长度的原始二进制数据缓冲区的底层对象。它本身不提供直接操作其内容的方法，需要通过类型化数组或DataView对象来访问。

// ‌主要作用‌：

// 作为二进制数据的底层存储容器
// 与Web API(如File API、Fetch API)交互的基础
// 实现内存共享和高效数据传输
// 3. Uint8Array
// Uint8Array是类型化数组(TypedArray)的一种，表示一个8位无符号整型数组，用于操作ArrayBuffer中的二进制数据。它是JavaScript操作二进制数据的主要接口之一。

// ‌主要作用‌：

// 以字节为单位访问和操作二进制数据
// 与ArrayBuffer配合实现内存高效利用
// 处理网络协议、文件格式等二进制结构
// 二、技术细节与比较
// Buffer详解
// ‌创建方式‌：

// javascript
// Copy Code
// // 创建长度为10的Buffer
// const buf1 = Buffer.alloc(10);

// // 从数组创建
// const buf2 = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);

// // 从字符串创建
// const buf3 = Buffer.from('Hello', 'utf8');
// ‌核心特性‌：

// 内存分配在V8堆外，不受垃圾回收机制影响
// 支持多种编码转换(utf8, base64, hex等)
// 提供丰富的操作方法(slice, concat, compare等)
// ArrayBuffer详解
// ‌创建与使用‌：

// javascript
// Copy Code
// // 创建8字节的ArrayBuffer
// const buffer = new ArrayBuffer(8);

// // 通过视图访问
// const view = new Uint8Array(buffer);
// view[0] = 42;
// ‌核心特性‌：

// 固定长度，创建后无法调整大小
// 不能直接操作，必须通过视图访问
// 支持传输(Transferable)和共享(SharedArrayBuffer)
// Uint8Array详解
// ‌创建方式‌：

// javascript
// Copy Code
// // 从长度创建
// const uint8 = new Uint8Array(4);

// // 从ArrayBuffer创建
// const buffer = new ArrayBuffer(8);
// const uint8View = new Uint8Array(buffer);

// // 从数组创建
// const uint8FromArray = new Uint8Array([1, 2, 3, 4]);
// ‌核心特性‌：

// 每个元素为0-255的无符号8位整数
// 自动处理溢出(值>255会取模256)
// 提供标准数组方法(map, filter, reduce等)
// 三、相互关系与区别
// 层级关系
// text
// Copy Code
// ArrayBuffer (原始二进制数据)
//    ↳ TypedArray (如Uint8Array) 或 DataView (访问接口)

// Buffer (Node.js对Uint8Array的优化实现)
// 主要区别
// 特性	Buffer	ArrayBuffer	Uint8Array
// 环境	Node.js特有	浏览器/Node.js	浏览器/Node.js
// 直接操作	支持	不支持	支持
// 编码转换	内置支持	不支持	不支持
// 内存位置	V8堆外	不确定	不确定
// 性能优化	高度优化	一般	一般
// 四、典型应用场景
// Buffer的典型应用
// ‌文件操作‌：读写二进制文件(如图片、PDF等)

// javascript
// Copy Code
// const fs = require('fs');
// const imageBuffer = fs.readFileSync('image.png');
// ‌网络通信‌：处理TCP/UDP数据包

// javascript
// Copy Code
// const net = require('net');
// const server = net.createServer((socket) => {
//   socket.on('data', (buffer) => {
//     // 处理接收到的二进制数据
//   });
// });
// ‌加密操作‌：处理加密算法的输入输出

// javascript
// Copy Code
// const crypto = require('crypto');
// const hash = crypto.createHash('sha256');
// hash.update(Buffer.from('secret data'));
// ArrayBuffer/Uint8Array的典型应用
// ‌Web API交互‌：处理Fetch响应、Blob数据

// javascript
// Copy Code
// fetch('data.bin')
//   .then(response => response.arrayBuffer())
//   .then(buffer => {
//     const uint8Array = new Uint8Array(buffer);
//   });
// ‌WebAssembly‌：内存共享与数据交换

// javascript
// Copy Code
// const wasmMemory = new WebAssembly.Memory({ initial: 1 });
// const wasmBuffer = new Uint8Array(wasmMemory.buffer);
// ‌Canvas图像处理‌：像素级操作

// javascript
// Copy Code
// const canvas = document.getElementById('canvas');
// const ctx = canvas.getContext('2d');
// const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// const uint8Array = imageData.data; // Uint8ClampedArray
// 五、性能考量与最佳实践
// 性能优化建议
// ‌避免频繁分配‌：重用Buffer/ArrayBuffer对象
// ‌选择合适视图‌：根据数据特性选择TypedArray类型
// ‌批量操作‌：使用set()方法而非逐个元素赋值
// ‌内存共享‌：利用Transferable对象减少拷贝
// 安全注意事项
// ‌初始化内存‌：新分配的Buffer/ArrayBuffer可能包含旧数据

// javascript
// Copy Code
// // 安全方式
// const safeBuf = Buffer.alloc(10); // 自动清零
// const unsafeBuf = Buffer.allocUnsafe(10); // 可能包含敏感数据
// ‌边界检查‌：操作前验证长度避免溢出

// ‌类型转换‌：注意不同编码/字节序的影响

// 六、总结
// JavaScript中的Buffer、ArrayBuffer和Uint8Array构成了处理二进制数据的完整体系。Buffer是Node.js优化的二进制处理工具，适合I/O密集型操作；ArrayBuffer是浏览器和Node.js通用的底层二进制容器；Uint8Array则是操作二进制数据的主要接口。理解它们的特性和适用场景，能够帮助开发者高效处理网络协议、文件格式、加密数据等二进制任务，构建性能更优的JavaScript应用
